package cc.mrbird.febs.common.utils;


import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;

/**
 * HTTP请求工具类
 * 提供HTTP GET和POST请求的发送功能
 * 支持普通HTTP和HTTPS请求
 * 包含SSL证书验证的信任管理器
 * 
 * @author MrBird
 */
@Slf4j
public class HttpUtil {

    /**
     * HTTP请求头常量定义
     */
    private static final String USER_AGENT = "user-agent";
    private static final String USER_AGENT_VALUE = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)";
    private static final String CONNECTION = "connection";
    private static final String CONNECTION_VALUE = "Keep-Alive";
    private static final String ACCEPT = "accept";
    private static final String UTF8 = "utf-8";
    private static final String ACCEPT_CHARSET = "Accept-Charset";
    private static final String CONTENTTYPE = "contentType";
    private static final String SSL = "ssl";

    /**
     * 私有构造函数，防止实例化
     */
    protected HttpUtil() {

    }

    /**
     * 发送GET请求
     * 支持带参数的GET请求，参数将以查询字符串的形式附加到URL后
     *
     * @param url 请求的URL地址
     * @param param 请求参数，格式为name1=value1&name2=value2
     * @return 服务器响应的字符串内容
     * @throws IOException 当发生网络IO异常时抛出
     */
    public static String sendGet(String url, String param) throws IOException {
        String urlNameString = url;
        if (StringUtils.isNotBlank(param))
            urlNameString += "?" + param;
        URL realUrl = new URL(urlNameString);
        URLConnection connection = realUrl.openConnection();
        StringBuilder result = new StringBuilder();
        connection.setRequestProperty(USER_AGENT, USER_AGENT_VALUE);
        connection.setRequestProperty(CONNECTION, CONNECTION_VALUE);
        connection.setRequestProperty(ACCEPT, "*/*");
        connection.connect();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
        } catch (Exception e) {
            log.error("发送GET请求出现异常！", e);
        }
        return result.toString();
    }

    /**
     * 发送无参数的GET请求
     *
     * @param url 请求的URL地址
     * @return 服务器响应的字符串内容
     * @throws IOException 当发生网络IO异常时抛出
     */
    public static String sendGet(String url) throws IOException {
        return sendGet(url, null);
    }

    /**
     * 发送POST请求
     * 支持带参数的POST请求，参数将以表单数据的形式发送
     *
     * @param url 请求的URL地址
     * @param param 请求参数，格式为name1=value1&name2=value2
     * @return 服务器响应的字符串内容
     * @throws IOException 当发生网络IO异常时抛出
     */
    public static String sendPost(String url, String param) throws IOException {
        StringBuilder result = new StringBuilder();

        String urlNameString = url + "?" + param;
        URL realUrl = new URL(urlNameString);
        URLConnection conn = realUrl.openConnection();
        conn.setDoInput(true);
        conn.setDoOutput(true);
        conn.setRequestProperty(CONTENTTYPE, UTF8);
        conn.setRequestProperty(ACCEPT_CHARSET, UTF8);
        conn.setRequestProperty(USER_AGENT, USER_AGENT_VALUE);
        conn.setRequestProperty(CONNECTION, CONNECTION_VALUE);
        conn.setRequestProperty(ACCEPT, "*/*");
        try (PrintWriter out = new PrintWriter(conn.getOutputStream()); BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8))) {
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            out.flush();
            out.print(param);
        } catch (Exception e) {
            log.error("发送 POST 请求出现异常！", e);
        }
        return result.toString();
    }

    /**
     * 发送HTTPS POST请求
     * 使用自定义的SSL信任管理器，忽略证书验证
     * 适用于需要访问自签名证书的HTTPS服务
     *
     * @param url 请求的URL地址
     * @param param 请求参数，格式为name1=value1&name2=value2
     * @return 服务器响应的字符串内容
     */
    public static String sendSSLPost(String url, String param) {
        StringBuilder result = new StringBuilder();
        String urlNameString = url + "?" + param;
        try {
            SSLContext sc = SSLContext.getInstance(SSL);
            sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
            URL console = new URL(urlNameString);
            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
            conn.setRequestProperty(ACCEPT, "*/*");
            conn.setRequestProperty(CONNECTION, CONNECTION_VALUE);
            conn.setRequestProperty(USER_AGENT, USER_AGENT_VALUE);
            conn.setRequestProperty(ACCEPT_CHARSET, UTF8);
            conn.setRequestProperty(CONTENTTYPE, UTF8);
            conn.setDoOutput(true);
            conn.setDoInput(true);

            conn.setSSLSocketFactory(sc.getSocketFactory());
            conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
            conn.connect();
            InputStream is = conn.getInputStream();
            BufferedReader indata = new BufferedReader(new InputStreamReader(is));
            String ret = "";
            while (ret != null) {
                ret = indata.readLine();
                if (ret != null && !ret.trim().equals("")) {
                    result.append(ret);
                }
            }
            conn.disconnect();
            indata.close();
        } catch (Exception e) {
            log.error("发送SSL POST 请求出现异常！", e);
        }
        return result.toString();
    }

    /**
     * 自定义SSL信任管理器
     * 信任所有证书，用于处理自签名证书的情况
     */
    private static class TrustAnyTrustManager implements X509TrustManager {
        /**
         * 不验证客户端证书
         */
        public void checkClientTrusted(X509Certificate[] chain, String authType) {
            //trust anything
        }

        /**
         * 不验证服务器证书
         */
        public void checkServerTrusted(X509Certificate[] chain, String authType) {
            //trust anything
        }

        /**
         * 返回空的证书数组
         */
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    /**
     * 自定义主机名验证器
     * 信任所有主机名，用于处理自签名证书的情况
     */
    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        /**
         * 验证主机名，始终返回true
         */
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

}
